#!/bin/bash

set -Eo pipefail

# codec pool conf path
VERSION_CONF_PATH=/opt/master/conf/version.conf
MASTER_CONF_PATH=/opt/master/conf/master.conf
ENCODER_CONF_PATH=/opt/worker/conf/encoder.conf
ENCODER_SERVICE_PATH=/opt/worker/conf/service.conf

# codec pool bin path
MASTER_BIN_PATH=/opt/master/masterServer

# max try start times
MAX_TRY_START_TIMES=3

# codec pattern
CODEC_PATTERN_POOL=POOL
CODEC_PATTERN_DIRECT=DIRECT

# log file
LOG_FILE_PATH=/var/log/master/config-codecpool.log

function echo_error()
{
    echo -en "$*\n"
    echo -en "[$(date +"%Y-%m-%d %H:%M:%S")][ERROR] $*\n" >> "${LOG_FILE_PATH}"
}

function echo_info()
{
    echo -en "$*\n"
    echo -en "[$(date +"%Y-%m-%d %H:%M:%S")][INFO] $*\n" >> "${LOG_FILE_PATH}"
}

function usage()
{
    printf "usage: config code pool [OPTIONS]...\n"
    printf "       -m master port, Specifies the port of the master, range: (1024,65535).\n"
    printf "       -c health check port, Specifies the port of health check, range: (1024,65535).\n"
    printf "       -u health check url, Specifies the url of health check, must start with /.\n"
    if [[ -n "${gpu_instance}" ]]; then
        printf "       -e encode type, Specifies the encode type, optionals: H264/MIX.\n"
    fi
    printf "       -r resolution type, Specifies the resolution type of encode, optionals: 720P/1080P.\n"
    printf "       -f encode frame fps, Specifies the frame rate of encode, optionals: 20/30/60.\n"
    printf "       -p worker pattern, Specifies the pattern of worker, optionals: POOL/DIRECT.\n"
}

function config_worker_pattern()
{
    echo_info "start to config worker pattern ${ENCODER_CONF_PATH}"
    if [[ ${worker_pattern} != "" ]];then
        sed -i "s/^pattern=.*/pattern=${worker_pattern}/g" ${ENCODER_CONF_PATH}
        echo_info "config worker pattern ${worker_pattern} success"
    fi
    echo_info "config worker pattern ${ENCODER_CONF_PATH} success"
}

function config_master_conf()
{
    echo_info "start to config master conf ${MASTER_CONF_PATH}"
    if [[ ${master_port} != "" ]];then
        sed -i "s/^port=.*/port=${master_port}/g" ${MASTER_CONF_PATH}
        echo_info "config master port ${master_port} success"
    fi

    if [[ ${healthcheck_port} != "" ]];then
        sed -i "s/^healthCheckPort=.*/healthCheckPort=${healthcheck_port}/g" ${MASTER_CONF_PATH}
        echo_info "config health check port ${healthcheck_port} success"
    fi

    if [[ ${healthcheck_url} != "" ]];then
        sed -i "s|^healthCheckUrl=.*|healthCheckUrl=${healthcheck_url}|g" ${MASTER_CONF_PATH}
        echo_info "config health check port ${healthcheck_url} success"
    fi
    echo_info "config master conf ${MASTER_CONF_PATH} success"
}

function config_service_conf()
{
    echo_info "start to config service conf ${ENCODER_SERVICE_PATH}"
    if [[ ${master_port} != "" ]];then
        sed -i "s/^port=.*/port=${master_port}/g" ${ENCODER_SERVICE_PATH}
        echo_info "config master port ${master_port} in ${ENCODER_SERVICE_PATH} success"
    fi

    echo_info "config service conf ${ENCODER_SERVICE_PATH} success"
}

function config_encoder_conf()
{
    echo_info "start to config encoder conf ${ENCODER_CONF_PATH}"
    if [[ ${encode_type} != "" ]];then
        sed -i "s/^videoFrameType=.*/videoFrameType=${encode_type}/g" ${ENCODER_CONF_PATH}
        echo_info "config encode type ${encode_type} success"
    fi
    if [[ ${resolution_type} != "" ]];then
        sed -i "s/^resolution=.*/resolution=${resolution_type}/g" ${ENCODER_CONF_PATH}
        echo_info "config resolution ${resolution_type} success"
    fi
    if [[ ${framerate_type} != "" ]] && [[ ${worker_pattern} == ${CODEC_PATTERN_POOL} ]];then
        sed -i "s/^frameRate=.*/frameRate=${framerate_type}/g" ${ENCODER_CONF_PATH}
        echo_info "config frameRate ${framerate_type} success"
    fi
    echo_info "config encoder conf ${ENCODER_CONF_PATH} success"
}

function start_master()
{
    local start_times=0
    local ret
    export LD_LIBRARY_PATH=/usr/local/lib
    while ((${start_times} <= MAX_TRY_START_TIMES))
    do
        start_times=$[start_times + 1]
        echo_info "start master server, times: ${start_times}"
        ${MASTER_BIN_PATH} -c ${MASTER_CONF_PATH} > /dev/null 2>&1 &
        ret=$?
        pid=$(ps -ef | grep masterServer | grep -v grep | awk '{print $2}')
        if [[ "${pid}" != "" ]] && [[ "${ret}" == "0" ]];then
            echo_info "start master server success, pid: ${pid}"
            return
        else
            echo_error "start master server failed, need to start again! return is ${ret}"
        fi
    done
    echo_error "start master server failed"
}

function restart_master()
{
    echo_info "start to restart master server"
    pid=$(ps -ef | grep masterServer | grep -v grep | awk '{print $2}')
    if [[ ${pid} != "" ]];then
        echo_info "need to stop masterServer, pid is ${pid}"
        kill -15 ${pid}
    fi

    start_master
    echo_info "restart master server success"
}

function restart_worker()
{
    local start_times=0
    local ret
    export LD_LIBRARY_PATH=/usr/local/lib
    while ((${start_times} <= MAX_TRY_START_TIMES))
    do
        start_times=$[start_times + 1]
        echo_info "start work server, times: ${start_times}"
        /opt/worker/reset.sh
        ret=$?
        if [[ "${ret}" != "0" ]];then
            echo_error "start worker failed, need to start again! return is ${ret}"
        else
            echo_info "start worker success"
            return;
        fi
    done
    echo_error "restart worker failed"
    exit 1
}

function check_encode_type()
{
    if [[ ! ${encode_type} ]];then
        return 0
    fi
    if [[ "${encode_type}" != "H264" ]] && [[ "${encode_type}" != "H265" ]] && [[ "${encode_type}" != "MIX" ]];then
        echo_error "encode type ${encode_type} is invalid, need to choose encode type from H264/H265/MIX"
        exit 1
    fi
}

function check_resolution_and_framerate_type()
{
    if [[ ! ${resolution_type} ]] && [[ ! ${framerate_type} ]];then
        return 0
    fi

    if [[ ! ${resolution_type} ]];then
        resolution_type=$(cat "${ENCODER_CONF_PATH}" | grep "^resolution" | awk -F'[=]' '{print $2}')
    fi

    if [[ ! ${framerate_type} ]];then
        framerate_type=$(cat "${ENCODER_CONF_PATH}" | grep "^frameRate" | awk -F'[=]' '{print $2}')
    fi

    if [[ "${resolution_type}" != "720P" ]] && [[ "${resolution_type}" != "1080P" ]];then
        echo_error "resolution type ${resolution_type} is invalid, need to choose resolution type from 720P/1080P"
        exit 1
    fi

    if [[ "${framerate_type}" != "20" ]] && [[ "${framerate_type}" != "30" ]] && [[ "${framerate_type}" != "60" ]];then
        echo_error "framerate type ${framerate_type} is invalid, need to choose framerate type from 20/30/60"
        exit 1
    fi
}

function check_worker_pattern()
{
    if [[ ! ${worker_pattern} ]];then
        worker_pattern=${CODEC_PATTERN_POOL}
        return 0
    fi

    if [[ ${worker_pattern} != ${CODEC_PATTERN_POOL} ]] && [[ "${worker_pattern}" != ${CODEC_PATTERN_DIRECT} ]];then
        echo_error "worker pattern ${worker_pattern} is invalid, need to choose worker pattern from POOL/DIRECT"
        exit 1
    fi
}

function check_url()
{
    if [[ ! ${healthcheck_url} ]];then
        return 0
    fi

    if [[ ${healthcheck_url:0:1} != "/" ]];then
        echo_error "healthcheck_url ${healthcheck_url} is invalid, must start with /"
        exit 1
    fi
}

function check_port()
{
    local port=$1
    if [[ ! ${port} ]];then
        return 0
    fi

    if [[ ${port} -le 1024 ]] || [[ $port -ge 65535 ]];then
        echo_error "port ${port} is invalid, need to choose from 1024~65535"
        exit 1
    fi
}

function get_version()
{
    version=$(cat "${VERSION_CONF_PATH}" | grep "^version" | awk -F'[=]' '{print $2}')
    echo_info "codec pool version is ${version}"
}

function main()
{
    local gpu_instance=$(which nvidia-smi)
    local support_opts="m:c:u:e:r:f:p:"
    if [[ -z "${gpu_instance}" ]]; then
        support_opts="m:c:u:r:f:p:"
    fi

    local version
    local master_port
    local healthcheck_port
    local healthcheck_url
    local encode_type
    local resolution_type
    local framerate_type
    local worker_pattern
    local need_restart_worker=0

    while getopts ${support_opts} opt; do
        case ${opt} in
            m)
                master_port="$OPTARG" ;;
            c)
                healthcheck_port="$OPTARG" ;;
            u)
                healthcheck_url="$OPTARG" ;;
            e)
                encode_type="$OPTARG" ;;
            r)
                resolution_type="$OPTARG" ;;
            f)
                framerate_type="$OPTARG" ;;
            p)
                worker_pattern="$OPTARG" ;;
            *)
                usage
                exit 1
            ;;
        esac
    done
    echo > ${LOG_FILE_PATH}

    get_version
    check_port ${master_port}
    check_port ${healthcheck_port}
    check_url
    check_encode_type
    check_resolution_and_framerate_type
    check_worker_pattern

    if [[ "${worker_pattern}" != "" ]];then
        config_worker_pattern
    fi

    if [[ "${master_port}" != "" ]] || [[ "${healthcheck_port}" != "" ]] || [[ "${healthcheck_url}" != "" ]];then
        config_master_conf
        restart_master
    fi

    if [[ "${master_port}" != "" ]];then
        config_service_conf ${master_port}
        need_restart_worker=1
    fi

    if [[ "${encode_type}" != "" ]] || [[ "${resolution_type}" != "" ]] || [[ "${framerate_type}" != "" ]];then
        config_encoder_conf ${encode_type} ${resolution_type} ${framerate_type}
        need_restart_worker=1
    fi

    if [[ "${worker_pattern}" == ${CODEC_PATTERN_DIRECT} ]];then
        need_restart_worker=1
    fi

    if [[ ${need_restart_worker} == 1 ]];then
        restart_worker
    fi
}

main "$@"